From e143339810bf8f3b3e5f500306a4a7219b520cd0 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Fri, 12 Dec 2003 16:43:23 +0000 Subject: [PATCH] bitkeeper revision 1.645.1.1 (3fd9f02bxWKGgV_bPDcD98xGu_WfmA) Many files: Update the VBD interface. --- tools/examples/createlinuxdom.py | 20 ++-- tools/examples/mynewdom.py | 20 ++-- tools/xc/lib/xc.h | 34 ++++-- tools/xc/lib/xc_vbd.c | 135 ++++++++++++++++++---- tools/xc/py/Xc.c | 189 ++++++++++++++++++++++++++----- xen/drivers/block/xen_block.c | 17 ++- xen/drivers/block/xen_vbd.c | 176 +++++++++++++++++++++------- xen/include/hypervisor-ifs/vbd.h | 83 +++++++------- xen/include/xeno/vbd.h | 22 ++-- 9 files changed, 513 insertions(+), 183 deletions(-) diff --git a/tools/examples/createlinuxdom.py b/tools/examples/createlinuxdom.py index 57b2b0760a..d01a2ea0b7 100755 --- a/tools/examples/createlinuxdom.py +++ b/tools/examples/createlinuxdom.py @@ -77,11 +77,11 @@ if root_partn: print "Error creating root VBD" xc.domain_destroy ( dom=id ) sys.exit() - if xc.vbd_add_extent( dom=id, - vbd=root_info[0], - device=root_info[1], - start_sector=root_info[2], - nr_sectors=root_info[3] ): + if xc.vbd_grow( dom=id, + vbd=root_info[0], + device=root_info[1], + start_sector=root_info[2], + nr_sectors=root_info[3] ): print "Error populating root VBD" xc.domain_destroy ( dom=id ) sys.exit() @@ -91,11 +91,11 @@ if usr_partn: print "Error creating usr VBD" xc.domain_destroy ( dom=id ) sys.exit() - if xc.vbd_add_extent( dom=id, - vbd=usr_info[0], - device=usr_info[1], - start_sector=usr_info[2], - nr_sectors=usr_info[3] ): + if xc.vbd_grow( dom=id, + vbd=usr_info[0], + device=usr_info[1], + start_sector=usr_info[2], + nr_sectors=usr_info[3] ): print "Error populating usr VBD" xc.domain_destroy ( dom=id ) sys.exit() diff --git a/tools/examples/mynewdom.py b/tools/examples/mynewdom.py index b3df7853bf..29c8a35419 100755 --- a/tools/examples/mynewdom.py +++ b/tools/examples/mynewdom.py @@ -83,11 +83,11 @@ if root_partn: print "Error creating root VBD" xc.domain_destroy ( dom=id ) sys.exit() - if xc.vbd_add_extent( dom=id, - vbd=root_info[0], - device=root_info[1], - start_sector=root_info[2], - nr_sectors=root_info[3] ): + if xc.vbd_grow( dom=id, + vbd=root_info[0], + device=root_info[1], + start_sector=root_info[2], + nr_sectors=root_info[3] ): print "Error populating root VBD" xc.domain_destroy ( dom=id ) sys.exit() @@ -97,11 +97,11 @@ if usr_partn: print "Error creating usr VBD" xc.domain_destroy ( dom=id ) sys.exit() - if xc.vbd_add_extent( dom=id, - vbd=usr_info[0], - device=usr_info[1], - start_sector=usr_info[2], - nr_sectors=usr_info[3] ): + if xc.vbd_grow( dom=id, + vbd=usr_info[0], + device=usr_info[1], + start_sector=usr_info[2], + nr_sectors=usr_info[3] ): print "Error populating usr VBD" xc.domain_destroy ( dom=id ) sys.exit() diff --git a/tools/xc/lib/xc.h b/tools/xc/lib/xc.h index 6b025a1c8b..246d9cfbf9 100644 --- a/tools/xc/lib/xc.h +++ b/tools/xc/lib/xc.h @@ -34,6 +34,9 @@ int xc_domain_stop(int xc_handle, int xc_domain_destroy(int xc_handle, unsigned int domid, int force); +int xc_domain_pincpu(int xc_handle, + unsigned int domid, + int cpu); int xc_domain_getinfo(int xc_handle, unsigned int first_domid, unsigned int max_doms, @@ -93,6 +96,11 @@ typedef struct { unsigned long nr_sectors; } xc_vbd_t; +typedef struct { + unsigned short real_device; + unsigned long start_sector; + unsigned long nr_sectors; +} xc_vbdextent_t; int xc_vbd_create(int xc_handle, unsigned int domid, @@ -101,18 +109,24 @@ int xc_vbd_create(int xc_handle, int xc_vbd_destroy(int xc_handle, unsigned int domid, unsigned short vbdid); -int xc_vbd_add_extent(int xc_handle, +int xc_vbd_grow(int xc_handle, + unsigned int domid, + unsigned short vbdid, + xc_vbdextent_t *extent); +int xc_vbd_shrink(int xc_handle, + unsigned int domid, + unsigned short vbdid); +int xc_vbd_setextents(int xc_handle, unsigned int domid, unsigned short vbdid, - unsigned short real_device, - unsigned long start_sector, - unsigned long nr_sectors); -int xc_vbd_delete_extent(int xc_handle, - unsigned int domid, - unsigned short vbdid, - unsigned short real_device, - unsigned long start_sector, - unsigned long nr_sectors); + unsigned int nr_extents, + xc_vbdextent_t *extents); +int xc_vbd_getextents(int xc_handle, + unsigned int domid, + unsigned short vbdid, + unsigned int max_extents, + xc_vbdextent_t *extents, + int *writeable); int xc_vbd_probe(int xc_handle, unsigned int domid, unsigned int max_vbds, diff --git a/tools/xc/lib/xc_vbd.c b/tools/xc/lib/xc_vbd.c index 914206c0f4..b309ed28d2 100644 --- a/tools/xc/lib/xc_vbd.c +++ b/tools/xc/lib/xc_vbd.c @@ -35,42 +35,129 @@ int xc_vbd_destroy(int xc_handle, } -int xc_vbd_add_extent(int xc_handle, - unsigned int domid, - unsigned short vbdid, - unsigned short real_device, - unsigned long start_sector, - unsigned long nr_sectors) +int xc_vbd_grow(int xc_handle, + unsigned int domid, + unsigned short vbdid, + xc_vbdextent_t *extent) { block_io_op_t op; - op.cmd = BLOCK_IO_OP_VBD_ADD; - op.u.add_params.domain = domid; - op.u.add_params.vdevice = vbdid; - op.u.add_params.extent.device = real_device; - op.u.add_params.extent.start_sector = start_sector; - op.u.add_params.extent.nr_sectors = nr_sectors; + op.cmd = BLOCK_IO_OP_VBD_GROW; + op.u.grow_params.domain = domid; + op.u.grow_params.vdevice = vbdid; + op.u.grow_params.extent.device = extent->real_device; + op.u.grow_params.extent.start_sector = extent->start_sector; + op.u.grow_params.extent.nr_sectors = extent->nr_sectors; return do_block_io_op(xc_handle, &op); } -int xc_vbd_delete_extent(int xc_handle, - unsigned int domid, - unsigned short vbdid, - unsigned short real_device, - unsigned long start_sector, - unsigned long nr_sectors) +int xc_vbd_shrink(int xc_handle, + unsigned int domid, + unsigned short vbdid) { block_io_op_t op; - op.cmd = BLOCK_IO_OP_VBD_REMOVE; - op.u.add_params.domain = domid; - op.u.add_params.vdevice = vbdid; - op.u.add_params.extent.device = real_device; - op.u.add_params.extent.start_sector = start_sector; - op.u.add_params.extent.nr_sectors = nr_sectors; + op.cmd = BLOCK_IO_OP_VBD_SHRINK; + op.u.shrink_params.domain = domid; + op.u.shrink_params.vdevice = vbdid; return do_block_io_op(xc_handle, &op); } +int xc_vbd_setextents(int xc_handle, + unsigned int domid, + unsigned short vbdid, + unsigned int nr_extents, + xc_vbdextent_t *extents) +{ + int i, rc; + block_io_op_t op; + xen_extent_t *real_extents = NULL; + + if ( nr_extents != 0 ) + { + real_extents = malloc(nr_extents * sizeof(xc_vbdextent_t)); + if ( (real_extents == NULL) || + (mlock(real_extents, nr_extents * sizeof(xc_vbdextent_t)) != 0) ) + { + if ( real_extents != NULL ) + free(real_extents); + return -ENOMEM; + } + + for ( i = 0; i < nr_extents; i++ ) + { + real_extents[i].device = extents[i].real_device; + real_extents[i].start_sector = extents[i].start_sector; + real_extents[i].nr_sectors = extents[i].nr_sectors; + } + } + + op.cmd = BLOCK_IO_OP_VBD_SET_EXTENTS; + op.u.setextents_params.domain = domid; + op.u.setextents_params.vdevice = vbdid; + op.u.setextents_params.nr_extents = nr_extents; + op.u.setextents_params.extents = real_extents; + rc = do_block_io_op(xc_handle, &op); + + if ( real_extents != NULL ) + { + (void)munlock(real_extents, nr_extents * sizeof(xc_vbdextent_t)); + free(real_extents); + } + + return rc; +} + + +int xc_vbd_getextents(int xc_handle, + unsigned int domid, + unsigned short vbdid, + unsigned int max_extents, + xc_vbdextent_t *extents, + int *writeable) +{ + int i, rc; + block_io_op_t op; + xen_extent_t *real_extents = malloc(max_extents * sizeof(xc_vbdextent_t)); + + if ( (real_extents == NULL) || + (mlock(real_extents, max_extents * sizeof(xc_vbdextent_t)) != 0) ) + { + if ( real_extents != NULL ) + free(real_extents); + return -ENOMEM; + } + + op.cmd = BLOCK_IO_OP_VBD_INFO; + op.u.info_params.domain = domid; + op.u.info_params.vdevice = vbdid; + op.u.info_params.maxextents = max_extents; + op.u.info_params.extents = real_extents; + rc = do_block_io_op(xc_handle, &op); + + (void)munlock(real_extents, max_extents * sizeof(xc_vbdextent_t)); + + if ( rc >= 0 ) + { + for ( i = 0; i < op.u.info_params.nextents; i++ ) + { + extents[i].real_device = real_extents[i].device; + extents[i].start_sector = real_extents[i].start_sector; + extents[i].nr_sectors = real_extents[i].nr_sectors; + } + + if ( writeable != NULL ) + *writeable = !!(op.u.info_params.mode & VBD_MODE_W); + + rc = op.u.info_params.nextents; + } + + free(real_extents); + + return rc; +} + + int xc_vbd_probe(int xc_handle, unsigned int domid, unsigned int max_vbds, diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c index 0676bd137b..e24a691172 100644 --- a/tools/xc/py/Xc.c +++ b/tools/xc/py/Xc.c @@ -387,52 +387,159 @@ static PyObject *pyxc_vbd_destroy(PyObject *self, return PyInt_FromLong(ret); } -static PyObject *pyxc_vbd_add_extent(PyObject *self, - PyObject *args, - PyObject *kwds) +static PyObject *pyxc_vbd_grow(PyObject *self, + PyObject *args, + PyObject *kwds) { XcObject *xc = (XcObject *)self; - unsigned int dom, vbd, device; - unsigned long start_sector, nr_sectors; - int ret; + unsigned int dom, vbd; + xc_vbdextent_t extent; + int ret; static char *kwd_list[] = { "dom", "vbd", "device", "start_sector", "nr_sectors", NULL }; if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiill", kwd_list, - &dom, &vbd, &device, - &start_sector, &nr_sectors) ) + &dom, &vbd, + &extent.real_device, + &extent.start_sector, + &extent.nr_sectors) ) return NULL; - ret = xc_vbd_add_extent(xc->xc_handle, dom, vbd, device, - start_sector, nr_sectors); + ret = xc_vbd_grow(xc->xc_handle, dom, vbd, &extent); return PyInt_FromLong(ret); } -static PyObject *pyxc_vbd_delete_extent(PyObject *self, - PyObject *args, - PyObject *kwds) +static PyObject *pyxc_vbd_shrink(PyObject *self, + PyObject *args, + PyObject *kwds) { XcObject *xc = (XcObject *)self; - unsigned int dom, vbd, device; - unsigned long start_sector, nr_sectors; + unsigned int dom, vbd; int ret; - static char *kwd_list[] = { "dom", "vbd", "device", - "start_sector", "nr_sectors", NULL }; + static char *kwd_list[] = { "dom", "vbd", NULL }; - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiill", kwd_list, - &dom, &vbd, &device, - &start_sector, &nr_sectors) ) + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, + &dom, &vbd) ) return NULL; - ret = xc_vbd_delete_extent(xc->xc_handle, dom, vbd, device, - start_sector, nr_sectors); + ret = xc_vbd_shrink(xc->xc_handle, dom, vbd); + + return PyInt_FromLong(ret); +} + +static PyObject *pyxc_vbd_setextents(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + PyObject *list, *dict, *obj; + + unsigned int dom, vbd; + xc_vbdextent_t *extents = NULL; + int ret, i, nr_extents; + + static char *kwd_list[] = { "dom", "vbd", "extents", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iio", kwd_list, + &dom, &vbd, &list) ) + goto fail; + + if ( (nr_extents = PyList_Size(list)) < 0 ) + goto fail; + + if ( nr_extents != 0 ) + { + extents = malloc(nr_extents * sizeof(xc_vbdextent_t)); + if ( extents == NULL ) + goto fail; + + for ( i = 0; i < nr_extents; i++ ) + { + dict = PyList_GetItem(list, i); + if ( !PyDict_Check(dict) ) + goto fail; + if ( ((obj = PyDict_GetItemString(dict, "device")) == NULL) || + !PyInt_Check(obj) ) + goto fail; + extents[i].real_device = (unsigned short)PyInt_AsLong(obj); + if ( ((obj = PyDict_GetItemString(dict,"start_sector")) == NULL) || + !PyInt_Check(obj) ) + goto fail; + extents[i].start_sector = PyInt_AsLong(obj); + if ( ((obj = PyDict_GetItemString(dict, "nr_sectors")) == NULL) || + !PyInt_Check(obj) ) + goto fail; + extents[i].nr_sectors = PyInt_AsLong(obj); + } + } + + ret = xc_vbd_setextents(xc->xc_handle, dom, vbd, nr_extents, extents); + + if ( extents != NULL ) + free(extents); return PyInt_FromLong(ret); + + fail: + if ( extents != NULL ) + free(extents); + return NULL; +} + +#define MAX_EXTENTS 1024 +static PyObject *pyxc_vbd_getextents(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + PyObject *list; + + unsigned int dom, vbd; + xc_vbdextent_t *extents; + int i, nr_extents, max_extents; + + static char *kwd_list[] = { "dom", "vbd", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, + &dom, &vbd) ) + return NULL; + + extents = malloc(MAX_EXTENTS * sizeof(xc_vbdextent_t)); + if ( extents == NULL ) + max_extents = 0; + else + max_extents = MAX_EXTENTS; + + nr_extents = xc_vbd_getextents(xc->xc_handle, dom, vbd, max_extents, + extents, NULL); + + if ( nr_extents <= 0 ) + { + list = PyList_New(0); + } + else + { + list = PyList_New(nr_extents); + for ( i = 0; i < nr_extents; i++ ) + { + PyList_SetItem( + list, i, + Py_BuildValue("{s:i,s:l,s:l}", + "device", extents[i].real_device, + "start_sector", extents[i].start_sector, + "nr_sectors", extents[i].nr_sectors)); + } + } + + if ( extents != NULL ) + free(extents); + + return list; } static PyObject *pyxc_vbd_probe(PyObject *self, @@ -647,10 +754,10 @@ static PyMethodDef pyxc_methods[] = { " vbd [int]: Identifier of the VBD.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, - { "vbd_add_extent", - (PyCFunction)pyxc_vbd_add_extent, + { "vbd_grow", + (PyCFunction)pyxc_vbd_grow, METH_VARARGS | METH_KEYWORDS, "\n" - "Add an extent to a virtual block device.\n" + "Grow a virtual block device by appending a new extent.\n" " dom [int]: Identifier of domain containing the VBD.\n" " vbd [int]: Identifier of the VBD.\n" " device [int]: Identifier of the real underlying block device.\n" @@ -658,17 +765,37 @@ static PyMethodDef pyxc_methods[] = { " nr_sectors [int]: Length, in sectors, of this extent.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, - { "vbd_delete_extent", - (PyCFunction)pyxc_vbd_delete_extent, + { "vbd_shrink", + (PyCFunction)pyxc_vbd_shrink, + METH_VARARGS | METH_KEYWORDS, "\n" + "Shrink a virtual block device by deleting its final extent.\n" + " dom [int]: Identifier of domain containing the VBD.\n" + " vbd [int]: Identifier of the VBD.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "vbd_setextents", + (PyCFunction)pyxc_vbd_setextents, METH_VARARGS | METH_KEYWORDS, "\n" - "Delete an extent from a virtual block device.\n" + "Set all the extent information for a virtual block device.\n" " dom [int]: Identifier of domain containing the VBD.\n" " vbd [int]: Identifier of the VBD.\n" - " device [int]: Identifier of the real underlying block device.\n" - " start_sector [int]: Real start sector of the extent.\n" - " nr_sectors [int]: Length, in sectors, of the extent.\n\n" + " extents [list of dicts]: Per-extent information.\n" + " device [int]: Identifier of the real underlying block device.\n" + " start_sector [int]: Real start sector of this extent.\n" + " nr_sectors [int]: Length, in sectors, of this extent.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, + { "vbd_getextents", + (PyCFunction)pyxc_vbd_getextents, + METH_VARARGS | METH_KEYWORDS, "\n" + "Get info on all the extents in a virtual block device.\n" + " dom [int]: Identifier of domain containing the VBD.\n" + " vbd [int]: Identifier of the VBD.\n\n" + "Returns: [list of dicts] per-extent information; empty on error.\n" + " device [int]: Identifier of the real underlying block device.\n" + " start_sector [int]: Real start sector of this extent.\n" + " nr_sectors [int]: Length, in sectors, of this extent.\n" }, + { "vbd_probe", (PyCFunction)pyxc_vbd_probe, METH_VARARGS | METH_KEYWORDS, "\n" diff --git a/xen/drivers/block/xen_block.c b/xen/drivers/block/xen_block.c index 78ba3c86b9..5103d85ffd 100644 --- a/xen/drivers/block/xen_block.c +++ b/xen/drivers/block/xen_block.c @@ -274,14 +274,19 @@ long do_block_io_op(block_io_op_t *u_block_io_op) ret = vbd_create(&op.u.create_params); break; - case BLOCK_IO_OP_VBD_ADD: - /* add an extent to a VBD */ - ret = vbd_add(&op.u.add_params); + case BLOCK_IO_OP_VBD_GROW: + /* append an extent to a VBD */ + ret = vbd_grow(&op.u.grow_params); break; - case BLOCK_IO_OP_VBD_REMOVE: - /* remove an extent from a VBD */ - ret = vbd_remove(&op.u.remove_params); + case BLOCK_IO_OP_VBD_SHRINK: + /* remove teh final extent from a VBD */ + ret = vbd_shrink(&op.u.shrink_params); + break; + + case BLOCK_IO_OP_VBD_SET_EXTENTS: + /* a fresh extent list for the given VBD */ + ret = vbd_setextents(&op.u.setextents_params); break; case BLOCK_IO_OP_VBD_DELETE: diff --git a/xen/drivers/block/xen_vbd.c b/xen/drivers/block/xen_vbd.c index 8607071b1b..f16adb6795 100644 --- a/xen/drivers/block/xen_vbd.c +++ b/xen/drivers/block/xen_vbd.c @@ -33,6 +33,7 @@ extern int scsi_probe_devices(xen_disk_info_t *xdi); /* XXX SMH: crappy 'hash function' .. fix when care. */ #define HSH(_x) ((_x) & (VBD_HTAB_SZ - 1)) + /* ** Create a new VBD; all this involves is adding an entry to the domain's ** vbd hash table; caller must be privileged. @@ -43,10 +44,10 @@ long vbd_create(vbd_create_t *create) vbd_t *new_vbd, **pv; long ret = 0; - if( !IS_PRIV(current) ) + if ( unlikely(!IS_PRIV(current)) ) return -EPERM; - if ( (p = find_domain_by_id(create->domain)) == NULL ) + if ( unlikely((p = find_domain_by_id(create->domain)) == NULL) ) { DPRINTK("vbd_create attempted for non-existent domain %d\n", create->domain); @@ -59,7 +60,7 @@ long vbd_create(vbd_create_t *create) *pv != NULL; pv = &(*pv)->next ) { - if ( (*pv)->vdevice == create->vdevice ) + if ( unlikely((*pv)->vdevice == create->vdevice) ) { DPRINTK("vbd_create attempted for already existing vbd\n"); ret = -EINVAL; @@ -69,10 +70,16 @@ long vbd_create(vbd_create_t *create) break; } - new_vbd = kmalloc(sizeof(vbd_t), GFP_KERNEL); + if ( unlikely((new_vbd = kmalloc(sizeof(vbd_t), GFP_KERNEL)) == NULL) ) + { + DPRINTK("vbd_create: out of memory\n"); + ret = -ENOMEM; + goto out; + } + new_vbd->vdevice = create->vdevice; new_vbd->mode = create->mode; - new_vbd->extents = (xen_extent_le_t *)NULL; + new_vbd->extents = NULL; new_vbd->next = *pv; *pv = new_vbd; @@ -83,44 +90,48 @@ long vbd_create(vbd_create_t *create) return ret; } -/* -** Add an extent to an existing VBD; fails if the VBD doesn't exist. -** Doesn't worry about overlapping extents (e.g. merging etc) for now. -*/ -long vbd_add(vbd_add_t *add) + +/* Grow a VBD by appending a new extent. Fails if the VBD doesn't exist. */ +long vbd_grow(vbd_grow_t *grow) { struct task_struct *p; xen_extent_le_t **px, *x; vbd_t *v; long ret = 0; - if ( !IS_PRIV(current) ) + if ( unlikely(!IS_PRIV(current)) ) return -EPERM; - if ( (p = find_domain_by_id(add->domain)) == NULL ) + if ( unlikely((p = find_domain_by_id(grow->domain)) == NULL) ) { - DPRINTK("vbd_add attempted for non-existent domain %d\n", - add->domain); + DPRINTK("vbd_grow: attempted for non-existent domain %d\n", + grow->domain); return -EINVAL; } spin_lock(&p->vbd_lock); - for ( v = p->vbdtab[HSH(add->vdevice)]; v != NULL; v = v->next ) - if ( v->vdevice == add->vdevice ) + for ( v = p->vbdtab[HSH(grow->vdevice)]; v != NULL; v = v->next ) + if ( v->vdevice == grow->vdevice ) break; - if ( v == NULL ) + if ( unlikely(v == NULL) ) { - DPRINTK("vbd_add; attempted to add extent to non-existent VBD.\n"); + DPRINTK("vbd_grow: attempted to append extent to non-existent VBD.\n"); ret = -EINVAL; goto out; } - x = kmalloc(sizeof(xen_extent_le_t), GFP_KERNEL); - x->extent.device = add->extent.device; - x->extent.start_sector = add->extent.start_sector; - x->extent.nr_sectors = add->extent.nr_sectors; + if ( unlikely((x = kmalloc(sizeof(xen_extent_le_t), GFP_KERNEL)) == NULL) ) + { + DPRINTK("vbd_grow: out of memory\n"); + ret = -ENOMEM; + goto out; + } + + x->extent.device = grow->extent.device; + x->extent.start_sector = grow->extent.start_sector; + x->extent.nr_sectors = grow->extent.nr_sectors; x->next = (xen_extent_le_t *)NULL; for ( px = &v->extents; *px != NULL; px = &(*px)->next ) @@ -134,7 +145,8 @@ long vbd_add(vbd_add_t *add) return ret; } -long vbd_remove(vbd_remove_t *remove) + +long vbd_shrink(vbd_shrink_t *shrink) { struct task_struct *p; xen_extent_le_t **px, *x; @@ -144,48 +156,126 @@ long vbd_remove(vbd_remove_t *remove) if ( !IS_PRIV(current) ) return -EPERM; - if ( (p = find_domain_by_id(remove->domain)) == NULL ) + if ( (p = find_domain_by_id(shrink->domain)) == NULL ) { - DPRINTK("vbd_remove attempted for non-existent domain %d\n", - remove->domain); + DPRINTK("vbd_shrink attempted for non-existent domain %d\n", + shrink->domain); return -EINVAL; } spin_lock(&p->vbd_lock); - for ( v = p->vbdtab[HSH(remove->vdevice)]; v != NULL; v = v->next ) - if ( v->vdevice == remove->vdevice ) + for ( v = p->vbdtab[HSH(shrink->vdevice)]; v != NULL; v = v->next ) + if ( v->vdevice == shrink->vdevice ) break; - if ( v == NULL ) + if ( unlikely(v == NULL) || unlikely(v->extents == NULL) ) { - DPRINTK("vbd_remove; attempt to remove ext from non-existent VBD.\n"); + DPRINTK("vbd_shrink: attempt to remove non-existent extent.\n"); ret = -EINVAL; goto out; } - for ( px = &v->extents; *px != NULL; px = &(*px)->next ) - if ( (*px)->extent.start_sector == remove->extent.start_sector ) - break; - - if ( ((x = *px) == NULL) || - (x->extent.nr_sectors != remove->extent.nr_sectors) || - (x->extent.device != remove->extent.device) ) + /* Find the last extent. We now know that there is at least one. */ + for ( px = &v->extents; (*px)->next != NULL; px = &(*px)->next ) + continue; + + x = *px; + *px = x->next; + kfree(x); + + out: + spin_unlock(&p->vbd_lock); + put_task_struct(p); + return ret; +} + + +long vbd_setextents(vbd_setextents_t *setextents) +{ + struct task_struct *p; + xen_extent_t e; + xen_extent_le_t *new_extents, *x, *t; + vbd_t *v; + int i; + long ret = 0; + + if ( !IS_PRIV(current) ) + return -EPERM; + + if ( (p = find_domain_by_id(setextents->domain)) == NULL ) + { + DPRINTK("vbd_setextents attempted for non-existent domain %d\n", + setextents->domain); + return -EINVAL; + } + + spin_lock(&p->vbd_lock); + + for ( v = p->vbdtab[HSH(setextents->vdevice)]; v != NULL; v = v->next ) + if ( v->vdevice == setextents->vdevice ) + break; + + if ( unlikely(v == NULL) ) { - DPRINTK("vbd_remove: attempt to remove non-matching extent.\n"); + DPRINTK("vbd_setextents: attempt to modify non-existent VBD.\n"); ret = -EINVAL; goto out; } - *px = x->next; - kfree(x); + /* Construct the new extent list. */ + new_extents = NULL; + for ( i = setextents->nr_extents; i >= 0; i++ ) + { + if ( unlikely(copy_from_user(&e, + &setextents->extents[i], + sizeof(e)) != 0) ) + { + DPRINTK("vbd_setextents: copy_from_user failed\n"); + ret = -EFAULT; + goto free_and_out; + } + + if ( unlikely((x = kmalloc(sizeof(xen_extent_le_t), GFP_KERNEL)) + == NULL) ) + { + DPRINTK("vbd_setextents: out of memory\n"); + ret = -ENOMEM; + goto free_and_out; + } + + x->extent = e; + x->next = new_extents; + + new_extents = x; + } + + /* Delete the old extent list _after_ successfully creating the new. */ + for ( x = v->extents; x != NULL; x = t ) + { + t = x->next; + kfree(x); + } + + /* Make the new list visible. */ + v->extents = new_extents; out: spin_unlock(&p->vbd_lock); put_task_struct(p); - return ret; + return ret; + + free_and_out: + /* Failed part-way through the new list. Delete all that we managed. */ + for ( x = new_extents; x != NULL; x = t ) + { + t = x->next; + kfree(x); + } + goto out; } + long vbd_delete(vbd_delete_t *delete) { struct task_struct *p; @@ -442,6 +532,8 @@ long vbd_info(vbd_info_t *info) extents = info->extents; for ( x = v->extents; x != NULL; x = x->next ) { + if ( info->nextents == info->maxextents ) + break; if ( copy_to_user(extents, &x->extent, sizeof(xen_extent_t)) ) { DPRINTK("vbd_info: copy_to_user failed\n"); @@ -449,7 +541,7 @@ long vbd_info(vbd_info_t *info) goto out; } extents++; - info->nextents++; + info->nextents++; } out: diff --git a/xen/include/hypervisor-ifs/vbd.h b/xen/include/hypervisor-ifs/vbd.h index e6dc6dafd6..df3ecba4ca 100644 --- a/xen/include/hypervisor-ifs/vbd.h +++ b/xen/include/hypervisor-ifs/vbd.h @@ -6,25 +6,24 @@ * Block I/O trap operations and associated structures. */ -#define BLOCK_IO_OP_SIGNAL 0 /* let xen know we have work to do */ +#define BLOCK_IO_OP_SIGNAL 0 /* let xen know we have work to do */ #define BLOCK_IO_OP_RESET 1 /* reset ring indexes on quiescent i/f */ #define BLOCK_IO_OP_RING_ADDRESS 2 /* returns machine address of I/O ring */ #define BLOCK_IO_OP_VBD_CREATE 3 /* create a new VBD for a given domain */ -#define BLOCK_IO_OP_VBD_ADD 4 /* add an extent to a given VBD */ -#define BLOCK_IO_OP_VBD_REMOVE 5 /* remove an extent from a given VBD */ -#define BLOCK_IO_OP_VBD_DELETE 6 /* delete a VBD */ -#define BLOCK_IO_OP_VBD_PROBE 7 /* query VBD information for a domain */ -#define BLOCK_IO_OP_VBD_INFO 8 /* query info about a particular VBD */ +#define BLOCK_IO_OP_VBD_GROW 4 /* append an extent to a given VBD */ +#define BLOCK_IO_OP_VBD_SHRINK 5 /* remove last extent from a given VBD */ +#define BLOCK_IO_OP_VBD_SET_EXTENTS 6 /* provide a fresh extent list for VBD */ +#define BLOCK_IO_OP_VBD_DELETE 7 /* delete a VBD */ +#define BLOCK_IO_OP_VBD_PROBE 8 /* query VBD information for a domain */ +#define BLOCK_IO_OP_VBD_INFO 9 /* query info about a particular VBD */ typedef struct _xen_extent { u16 device; - u16 unused; // pad + u16 unused; ulong start_sector; ulong nr_sectors; } xen_extent_t; - - #define VBD_MODE_R 0x1 #define VBD_MODE_W 0x2 @@ -33,44 +32,49 @@ typedef struct _xen_extent { typedef struct _vbd_create { - unsigned domain; // create VBD for this domain - u16 vdevice; // 16 bit id domain will refer to VBD as - u16 mode; // OR of { VBD_MODE_R , VBD_MODE_W } + unsigned domain; /* create VBD for this domain */ + u16 vdevice; /* id by which dom will refer to VBD */ + u16 mode; /* OR of { VBD_MODE_R , VBD_MODE_W } */ } vbd_create_t; -typedef struct _vbd_add { - unsigned domain; // domain in question - u16 vdevice; // 16 bit id domain refers to VBD as - xen_extent_t extent; // the extent to add to this VBD -} vbd_add_t; +typedef struct _vbd_grow { + unsigned domain; /* domain in question */ + u16 vdevice; /* 16 bit id domain refers to VBD as */ + xen_extent_t extent; /* the extent to add to this VBD */ +} vbd_grow_t; -typedef struct _vbd_remove { - unsigned domain; // domain in question - u16 vdevice; // 16 bit id domain refers to VBD as - xen_extent_t extent; // the extent to remove from this VBD -} vbd_remove_t; +typedef struct _vbd_shrink { + unsigned domain; /* domain in question */ + u16 vdevice; /* 16 bit id domain refers to VBD as */ +} vbd_shrink_t; +typedef struct _vbd_setextents { + unsigned domain; /* domain in question */ + u16 vdevice; /* 16 bit id domain refers to VBD as */ + u16 nr_extents; /* number of extents in the list */ + xen_extent_t *extents; /* the extents to add to this VBD */ +} vbd_setextents_t; typedef struct _vbd_delete { - unsigned domain; // domain in question - u16 vdevice; // 16 bit id domain refers to VBD as + unsigned domain; /* domain in question */ + u16 vdevice; /* 16 bit id domain refers to VBD as */ } vbd_delete_t; #define VBD_PROBE_ALL 0xFFFFFFFF typedef struct _vbd_probe { - unsigned domain; // domain in question or VBD_PROBE_ALL - xen_disk_info_t xdi; // where's our space for VBD/disk info + unsigned domain; /* domain in question or VBD_PROBE_ALL */ + xen_disk_info_t xdi; /* where's our space for VBD/disk info */ } vbd_probe_t; typedef struct _vbd_info { /* IN variables */ - unsigned domain; // domain in question - u16 vdevice; // 16 bit id domain refers to VBD as - u16 maxextents; // max no. of extents to return info for - xen_extent_t *extents; // pointer to space for array of extents + unsigned domain; /* domain in question */ + u16 vdevice; /* 16 bit id domain refers to VBD as */ + u16 maxextents; /* max # of extents to return info for */ + xen_extent_t *extents; /* pointer to space for extent list */ /* OUT variables */ - u16 nextents; // no of extents in the above - u16 mode; // VBD_MODE_{READONLY,READWRITE} + u16 nextents; /* # extents in the above list */ + u16 mode; /* VBD_MODE_{READONLY,READWRITE} */ } vbd_info_t; @@ -81,13 +85,14 @@ typedef struct block_io_op_st { /* no entry for BLOCK_IO_OP_SIGNAL */ /* no entry for BLOCK_IO_OP_RESET */ - unsigned long ring_mfn; - vbd_create_t create_params; - vbd_add_t add_params; - vbd_remove_t remove_params; - vbd_delete_t delete_params; - vbd_probe_t probe_params; - vbd_info_t info_params; + unsigned long ring_mfn; + vbd_create_t create_params; + vbd_grow_t grow_params; + vbd_shrink_t shrink_params; + vbd_setextents_t setextents_params; + vbd_delete_t delete_params; + vbd_probe_t probe_params; + vbd_info_t info_params; } u; } block_io_op_t; diff --git a/xen/include/xeno/vbd.h b/xen/include/xeno/vbd.h index f5fc383fcd..6734549418 100644 --- a/xen/include/xeno/vbd.h +++ b/xen/include/xeno/vbd.h @@ -1,8 +1,8 @@ /* ** include/xeno/vbd.h: ** -- xen internal declarations + prototypes for virtual block devices -** */ + #ifndef __VBD_H__ #define __VBD_H__ @@ -11,8 +11,8 @@ /* an entry in a list of xen_extent's */ typedef struct _xen_extent_le { - xen_extent_t extent; // an individual extent - struct _xen_extent_le *next; // and a pointer to the next + xen_extent_t extent; /* an individual extent */ + struct _xen_extent_le *next; /* and a pointer to the next */ } xen_extent_le_t; @@ -22,17 +22,18 @@ typedef struct _xen_extent_le { ** Each domain has a hash table to map from these to the relevant VBD. */ typedef struct _vbd { - unsigned short vdevice; // what the domain refers to this vbd as - unsigned short mode; // VBD_MODE_{READONLY,READWRITE} - xen_extent_le_t *extents; // list of xen_extents making up this vbd - struct _vbd *next; // for chaining in the hash table + unsigned short vdevice; /* what the domain refers to this vbd as */ + unsigned short mode; /* VBD_MODE_{READONLY,READWRITE} */ + xen_extent_le_t *extents; /* list of xen_extents making up this vbd */ + struct _vbd *next; /* for chaining in the hash table */ } vbd_t; -#define VBD_HTAB_SZ 16 // no. of entries in the vbd hash table. +#define VBD_HTAB_SZ 16 /* # entries in the vbd hash table. */ long vbd_create(vbd_create_t *create_params); -long vbd_add(vbd_add_t *add_params); -long vbd_remove(vbd_remove_t *remove_params); +long vbd_grow(vbd_grow_t *grow_params); +long vbd_shrink(vbd_shrink_t *shrink_params); +long vbd_setextents(vbd_setextents_t *setextents_params); long vbd_delete(vbd_delete_t *delete_params); long vbd_probe(vbd_probe_t *probe_params); long vbd_info(vbd_info_t *info_params); @@ -50,5 +51,4 @@ typedef struct { int vbd_translate(phys_seg_t *pseg, struct task_struct *p, int operation); - #endif /* __VBD_H__ */ -- 2.30.2